#include "cMesh.h"

#define SAFE_RELEASE(obj) if (obj) { obj->Release(); obj = nullptr; }

MeshData::MeshData( ID3D10Buffer * _VB /*= nullptr*/, ID3D10Buffer * _IB /*= nullptr*/ )
	: VertexBuffer(_VB), IndexBuffer(_IB), verticesCount(0), indicesCount(0), vertexSize(0)
{
}

MeshData::~MeshData()
{
	Flush();
}

bool MeshData::CreateBuffers( bool dynamic, 
							void * vData, size_t vSize, 
							void * iData, size_t iSize, 
							ID3D10Device * device )
{
	if(vSize > 0 && !vData)	return false;
	if(iSize > 0 && !iData)	return false;

	D3D10_BUFFER_DESC vBuffDesc;
	ZeroMemory(&vBuffDesc, sizeof(D3D10_BUFFER_DESC));
	D3D10_BUFFER_DESC iBuffDesc;
	ZeroMemory(&iBuffDesc, sizeof(D3D10_BUFFER_DESC));

	vBuffDesc.BindFlags			= D3D10_BIND_VERTEX_BUFFER;
	vBuffDesc.ByteWidth			= vSize;
	vBuffDesc.MiscFlags			= NULL;

	if(dynamic)
	{
		vBuffDesc.CPUAccessFlags	= D3D10_CPU_ACCESS_WRITE;
		vBuffDesc.Usage				= D3D10_USAGE_DYNAMIC;
	}
	else
	{
		vBuffDesc.CPUAccessFlags	= NULL;
		vBuffDesc.Usage				= D3D10_USAGE_DEFAULT;
	}

	if(vSize > 0)
	{
		D3D10_SUBRESOURCE_DATA data;
		ZeroMemory(&data, sizeof(D3D10_SUBRESOURCE_DATA));
		data.pSysMem = vData;

		if(FAILED(device->CreateBuffer(&vBuffDesc, &data, &VertexBuffer)))
			return false;
	}

	iBuffDesc.BindFlags			= D3D10_BIND_INDEX_BUFFER;
	iBuffDesc.ByteWidth			= iSize;
	iBuffDesc.MiscFlags			= NULL;

	if(dynamic)
	{
		iBuffDesc.CPUAccessFlags	= D3D10_CPU_ACCESS_WRITE;
		iBuffDesc.Usage				= D3D10_USAGE_DYNAMIC;
	}
	else
	{
		iBuffDesc.CPUAccessFlags	= NULL;
		iBuffDesc.Usage				= D3D10_USAGE_DEFAULT;
	}

	if(iSize > 0)
	{
		D3D10_SUBRESOURCE_DATA data;
		ZeroMemory(&data, sizeof(D3D10_SUBRESOURCE_DATA));
		data.pSysMem = iData;

		if(FAILED(device->CreateBuffer(&iBuffDesc, &data, &IndexBuffer)))
			return false;
	}

	return true;
}

void MeshData::Flush()
{
	SAFE_RELEASE(VertexBuffer);
	SAFE_RELEASE(IndexBuffer);
}

//////////////////////////////////////////////////////////////////////////

cMesh::cMesh( MeshDataPtr _Data /*= nullptr*/ )
	: Data(_Data), Scale(1.0f, 1.0f, 1.0f), Rotation(0.0f, 0.0f, 0.0f), Position(0.0f, 0.0f, 0.0f), bbox(Vector3F(0.0f, 0.0f, 0.0f), Vector3F(0.0f, 0.0f, 0.0f))
{
}

cMesh::~cMesh()
{
}

MeshDataPtr cMesh::GetData()
{
	return Data;
}

void cMesh::SetData( MeshDataPtr data )
{
	Data = data;
}

void cMesh::Draw( ID3D10Device * _device )
{
	if(Data != nullptr && Data->vertexSize != 0)
	{
		unsigned int stride = Data->vertexSize;
		unsigned int offset = 0;
		_device->IASetVertexBuffers(0, 1, &Data->VertexBuffer, &stride, &offset);
		_device->IASetIndexBuffer(Data->IndexBuffer, DXGI_FORMAT_R32_UINT, 0);
		_device->DrawIndexed(Data->indicesCount, 0, 0);
	}
}

void cMesh::SetPosition( D3DXVECTOR3 & _Position )
{
	Position = _Position;
}

void cMesh::SetScale( D3DXVECTOR3 & _Scale )
{
	Scale = _Scale;
}

void cMesh::SetRotation( D3DXVECTOR3 & _Rotation )
{
	Rotation = _Rotation;
}

D3DXMATRIX cMesh::GetWorldMatrix()
{
	D3DXMATRIX scale;
	D3DXMATRIX rot;
	D3DXMATRIX pos;
	D3DXMatrixScaling(&scale, Scale.x, Scale.y, Scale.z);
	D3DXMatrixRotationYawPitchRoll(&rot, Rotation.y, Rotation.x, Rotation.z);
	D3DXMatrixTranslation(&pos, Position.x, Position.y, Position.z);
	return scale * rot * pos;
}

D3DXVECTOR3 cMesh::GetPosition() const
{
	return Position;
}

D3DXVECTOR3 cMesh::GetScale() const
{
	return Scale;
}

D3DXVECTOR3 cMesh::GetRotation() const
{
	return Rotation;
}

void cMesh::SetBBox( AABB & box )
{
	bbox = box;
}

AABB cMesh::GetBBox() const
{
	return bbox;
}
